package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.apis.article.IArtcileClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutcoScanService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WmNewsAutoScanServiceImpl  implements WmNewsAutcoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private IArtcileClient artcileClient;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private Tess4jClient tess4jClient;

    /**
     * 文章审核
     *
     * @param id 文章ids
     */
    @Override
    @Async("customAsyncThreadPool")
    public void autoScan(Integer id) {



        //1、根据id查询文章详情
        WmNews wmNews = wmNewsMapper.selectById(id);

        //2、判断文章是否存在，如果不存在抛出异常
        if(wmNews==null){
            throw new RuntimeException("您要审核的文章不存在");
        }

        //3、判断文章状态必须是1(提交待审核)才需要审核
        if(wmNews.getStatus()!=WmNews.Status.SUBMIT.getCode()){
            throw new RuntimeException("您当前的文章不需要审核");
        }

        //4、从文章中提取文本、和图片地址
        //         key                value
        //map:   "content" :   "title"+"内容中的文字"
        //        "images":     ["http://19.....",""http://19...];
        Map map=handleTextAndImages(wmNews);

        //5、开始文本审核,审核失败需要将文章的状态进行修改
        boolean result = handleTextScan((String)map.get("content"),wmNews);

        //6、如果文本审核成功，则开始图片审核，否则审核业务结束
        if(!result){
            return;
        }

        //7、开始文本图片,审核失败需要将文章的状态进行修改
        result= handleImageScan((List<String>)map.get("images"),wmNews);

        //8、图片如果审核失败，业务结束
        if(!result){
            return;
        }

        //9、发起feign远程调用，需要将文章往ap_articlef进行同步
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,dto);
        dto.setId(wmNews.getArticleId());
        dto.setLayout(wmNews.getType());  //设置文章布局
        dto.setAuthorId(wmNews.getUserId().longValue());  //设置作者id
        dto.setCreatedTime(new Date());  //设置文章在ap_article的创建时间

        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if(wmUser!=null){
            dto.setAuthorName(wmUser.getName());   //设置作者名称
        }

        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if(wmChannel!=null){
            dto.setChannelName(wmChannel.getName());  //设置频道名称
        }

        //发起feign远程调用
        //ResponseResult  500 fein调用失
        ResponseResult response = artcileClient.saveArticle(dto);

        if(response.getCode()==200){
            //文章同步成功
            Object data = response.getData();  //获取文章的id

            //将文章id回填 到wm_news表中article_id列中
            wmNews.setArticleId(Long.valueOf(data.toString()));

            //10、修改文章的状态为9，同时将ap_article中的id 回填到wm_news表中的article_id
            updateStatus((short)9,"发布成功",wmNews);
        }


    }


    /**
     * 对文章图片进行审核
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImageScan(List<String> images, WmNews wmNews) {

        boolean result = true;
        //如果没有图片，则认为审核通过
        if(images==null || images.size()==0){
            return true;
        }

        //图片去重
        images= images.stream().distinct().collect(Collectors.toList());

        //到minｉｏ中下载图片，并存到imageList中
        List<byte[]>  imageList = new ArrayList<>();

        try {
            for (String imageURL : images) {
                //到minio中下载图片
                byte[] bytes = fileStorageService.downLoadFile(imageURL);

                //将字节数组转换成BufferdImage对象
                BufferedImage bimg = ImageIO.read(new ByteArrayInputStream(bytes));
                //获取图片中的文字
                String textInImage = tess4jClient.doOCR(bimg);
                //对图片中的文字进行审核
                boolean b = handleTextScan(textInImage, wmNews);
                //如果图片文字审核失败，则不需要继续审核
                if (!b) {
                    return false;
                }

                imageList.add(bytes);
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }

        //调用aliyun接口进行图片审核
        try {
            Map map = greenImageScan.imageScan(imageList);

            if("block".equals(map.get("suggestion"))){
                updateStatus((short)2,"图片审核失败",wmNews);
                result=false;
            }

            if("review".equals(map.get("suggestion"))){
                updateStatus((short)3,"图片需要人工审核",wmNews);
                result=false;
            }

        } catch (Exception e) {
            result=false;
          e.printStackTrace();
        }

        return result;
    }


    /**
     * 开始对文本内容进行审核
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {

        boolean result = true;

        if(StringUtils.isBlank(content)){
            return true;
        }


        //1、自敏感词审核
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(null);
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        //1.1创建dfa树
        SensitiveWordUtil.initMap(sensitiveList);
        //1.2 校验
        Map<String, Integer> senresult = SensitiveWordUtil.matchWords(content);

        if(senresult!=null && senresult.size()>0){
            updateStatus((short)2,"文章中包含有自敏感关键词",wmNews);
            return false;
        }


        try {
            Map map = greenTextScan.greeTextScan(content);

            if("block".equals(map.get("suggestion"))){   //审核失败
                updateStatus((short)2,"文本内容审核失败",wmNews);
                result=false;
            }

            if("review".equals(map.get("suggestion"))){   //需要人工审核
                updateStatus((short)3,"文本内容需要人工审核",wmNews);
                result=false;
            }


        } catch (Exception e) {
            result=false;
            e.printStackTrace();
        }

        return result;

    }



    //修改文章状态及原因
    private void updateStatus(short status,String response,WmNews wmNews){
        wmNews.setStatus(status);
        wmNews.setReason(response);
        wmNewsMapper.updateById(wmNews);
    }



    /**
     * 抽取文章中的文本和图片地址
     * @param wmNews
     * @return
     */
    private Map handleTextAndImages(WmNews wmNews) {
        StringBuilder content = new StringBuilder();
        List<String> images = new ArrayList();

        //将文章标题放到StringBuilder中
        content.append(wmNews.getTitle());
        //将封面图片的地址放到images这个集中
        if(StringUtils.isNotBlank(wmNews.getImages())){
            Collections.addAll(images,wmNews.getImages().split(","));
        }


        String content1 = wmNews.getContent();
        List<Map> maps = JSON.parseArray(content1, Map.class);
        for (Map map : maps) {
            if(map.get("type").equals("text")){
                content.append((String)map.get("value"));
            }

            if(map.get("type").equals("image")){
                images.add((String)map.get("value"));
            }
        }

        Map result = new HashMap();
        result.put("content",content.toString());
        result.put("images",images);

        return result;

    }
}
